﻿using System;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using System.Data.SqlClient;
using System.Collections.Generic;
using System.Diagnostics;
using DynORM.Interfaces.BLLMapper.Enum;
using DynORM.Enums;
using DynORM.BLLMapper;
using DynORM.Interfaces;
using DynORM.Mappers;
using DynORM.ReferenceObjects;

namespace UnitTestProject
{
    [TestClass]
    public class BLLAdaptiveMapperManyToManyUnitTests_MySQL
    {
        #region db creation and clean up
        //these two members are used only in CreateDB and DropDB methods
        //production code and test methods take this setting from the config file
        const DBMSTypes dbType = DBMSTypes.MySQL;
        static string dbName = "TestDB";
        static string pooling = "false";//otherwise it won't let drop db (db will be in use with connections in pool)
        static string connectionStringToDatabase = string.Format("Server={0};Database={1};Uid={2};pwd={3};Pooling={4}", "localhost", dbName, "testuser", "testuser", pooling);
        static string connectionStringToServer = string.Format("Server={0};Database={1};Uid={2};pwd={3};Pooling={4}", "localhost", "mysql", "testuser", "testuser", pooling);
        //A fresh MySQL server install will have 0 databases. The install script will run mysql_install_db after the server is running to create a mysql database, which MySQL uses to store users and privileges. Don't put your data there.

        [TestInitialize]
        public void TestInit()
        {
            DatabaseMapper.CreateDatabase(connectionStringToServer, dbType, new Database(dbName), true, false);
        }

        [TestCleanup]
        public void TestClean()
        {
            DatabaseMapper.DropDatabase(connectionStringToServer, dbType, dbName);
        }

        #endregion


        [TableAttribute(TableName = "TestBLLEntity1")]
        [ForeignKeyDeclarationAttribute(typeof(TestBLL2), RelationQuantity.ManyOrZeroToManyOrZero, "RelatedBLLObjs1", 0)]
        public class TestBLL1 : BLLSuperType
        {
            [PrimaryKeyAttribute("RowID", 0)]
            public Guid ID { get; set; }

            [FieldAttribute(FieldName = "SomeField1")]
            public int SomeProperty1 { get; set; }

            [FieldAttribute]
            public string SomeProperty2 { get; set; }

            private List<TestBLL2> relatedBLLObjs = new List<TestBLL2>();
            [DebuggerBrowsable(DebuggerBrowsableState.Never)]
            public List<TestBLL2> RelatedBLLObjs1
            {
                get
                {
                    Load(new BLLAdaptiveMapper(connectionStringToDatabase, dbType));
                    return this.relatedBLLObjs;
                }
                set
                {
                    Load(new BLLAdaptiveMapper(connectionStringToDatabase, dbType));
                    this.relatedBLLObjs = value;
                }
            }
        }

        [TableAttribute(TableName = "TestBLLEntity2")]
        [ForeignKeyDeclarationAttribute(typeof(TestBLL1), RelationQuantity.ManyOrZeroToManyOrZero, "RelatedBLLObjs2", 0)]
        public class TestBLL2 : BLLSuperType
        {
            [PrimaryKeyAttribute("RowID", 0)]
            public Guid ID { get; set; }

            [FieldAttribute(FieldName = "SomeField3")]
            public int SomeProperty3 { get; set; }

            [FieldAttribute]
            public string SomeProperty4 { get; set; }

            private List<TestBLL1> relatedBLLObjs = new List<TestBLL1>();
            [DebuggerBrowsable(DebuggerBrowsableState.Never)]
            public List<TestBLL1> RelatedBLLObjs2
            {
                get
                {
                    Load(new BLLAdaptiveMapper(connectionStringToDatabase, dbType));
                    return this.relatedBLLObjs;
                }
                set
                {
                    Load(new BLLAdaptiveMapper(connectionStringToDatabase, dbType));
                    this.relatedBLLObjs = value;
                }
            }
        }


        [TestMethod]
        public void SaveBLLObjTestParentChildManyToMany()
        {
            IBLLAdaptiveMapper mapper = new BLLAdaptiveMapper(connectionStringToDatabase, dbType);
            Guid id2 = Guid.NewGuid();
            TestBLL2 bllObj2 = (TestBLL2)mapper.Create(typeof(TestBLL2), id2);
            bllObj2.SomeProperty3 = 5;
            bllObj2.SomeProperty4 = "9";
            bllObj2.MarkAsLoaded();

            Guid id1 = Guid.NewGuid();
            TestBLL1 bllObj1 = (TestBLL1)mapper.Create(typeof(TestBLL1), id1);
            bllObj1.SomeProperty1 = 15;
            bllObj1.SomeProperty2 = "19";
            bllObj1.MarkAsLoaded();
            bllObj1.RelatedBLLObjs1.Add(bllObj2);

            bllObj2.RelatedBLLObjs2.Add(bllObj1);

            mapper.Write(bllObj2, true);

            mapper.Write(bllObj1, true);

            //mapper.DeleteDeep(bllObj1);
            mapper.DeleteCascade(bllObj2);
            mapper.DeleteCascade(bllObj1);
        }

        [TestMethod]
        public void ReadBLLObjTestParentChildManyToMany()
        {
            IBLLAdaptiveMapper mapper = new BLLAdaptiveMapper(connectionStringToDatabase, dbType);
            Guid id2 = Guid.NewGuid();
            TestBLL2 bllObj2 = (TestBLL2)mapper.Create(typeof(TestBLL2), id2);
            bllObj2.SomeProperty3 = 5;
            bllObj2.SomeProperty4 = "9";
            bllObj2.MarkAsLoaded();

            Guid id1 = Guid.NewGuid();
            TestBLL1 bllObj1 = (TestBLL1)mapper.Create(typeof(TestBLL1), id1);
            bllObj1.SomeProperty1 = 15;
            bllObj1.SomeProperty2 = "19";
            bllObj1.MarkAsLoaded();
            bllObj1.RelatedBLLObjs1.Add(bllObj2);

            bllObj2.RelatedBLLObjs2.Add(bllObj1);

            mapper.Write(bllObj2, true);
            mapper.Write(bllObj1, true);

            TestBLL2 retrievedBLLObj2 = (TestBLL2)mapper.Read(typeof(TestBLL2), id2);
            Assert.AreEqual<int>(bllObj2.SomeProperty3, retrievedBLLObj2.SomeProperty3);
            Assert.AreEqual<string>(bllObj2.SomeProperty4, retrievedBLLObj2.SomeProperty4);
            Assert.AreEqual<int>(bllObj2.RelatedBLLObjs2[0].SomeProperty1, retrievedBLLObj2.RelatedBLLObjs2[0].SomeProperty1);
            Assert.AreEqual<string>(bllObj2.RelatedBLLObjs2[0].SomeProperty2, retrievedBLLObj2.RelatedBLLObjs2[0].SomeProperty2);

            TestBLL1 retrievedBLLObj1 = (TestBLL1)mapper.Read(typeof(TestBLL1), id1);
            Assert.AreEqual<int>(bllObj1.SomeProperty1, retrievedBLLObj1.SomeProperty1);
            Assert.AreEqual<string>(bllObj1.SomeProperty2, retrievedBLLObj1.SomeProperty2);
            Assert.AreEqual<int>(bllObj1.RelatedBLLObjs1[0].SomeProperty3, retrievedBLLObj1.RelatedBLLObjs1[0].SomeProperty3);
            Assert.AreEqual<string>(bllObj1.RelatedBLLObjs1[0].SomeProperty4, retrievedBLLObj1.RelatedBLLObjs1[0].SomeProperty4);

            //mapper.DeleteDeep(bllObj1);
            mapper.DeleteCascade(bllObj2);
            mapper.DeleteCascade(bllObj1);
        }


    }
}
